﻿using System;
using System.Json;
using System.Text;
using System.Windows.Browser;
using System.Xml.Linq;

namespace jLight
{

    //Note:
    //Check if silverlight object in aspx has an id
    public class jQuery
    {
        private static ScriptObject _internaljQuery;

        public static EventHandler<EventArgs> Loaded;

        static jQuery(){}

        /// <summary>
        /// Loads a script.
        /// </summary>
        /// <param name="Script">The script.</param>
        /// <returns></returns>
        /// <exception cref="ArgumentNullException">Argument is null.</exception>
        private static ScriptObject LoadScript(string Script)
        {
            if (string.IsNullOrEmpty(Script)) throw new ArgumentNullException("Script");
            System.IO.Stream stream = typeof(jQuery).Assembly.GetManifestResourceStream(Script);
            if (stream != null)
            {
                var reader = new System.IO.StreamReader(stream);
                string script = reader.ReadToEnd();
                return (ScriptObject) HtmlPage.Window.Eval(script);
            }
            return null;
        }

        /// <summary>
        /// Checks if jQuery is loaded
        /// </summary>
        public static bool IsLoaded { get { return ((bool)HtmlPage.Window.Eval("typeof jQuery != 'undefined'")); } }


        /// <summary>
        /// Checks if jQuery is loaded
        /// </summary>
        private static bool IsPrototypeLoaded { get { return ((bool)HtmlPage.Window.Eval("typeof Prototype != 'undefined'")); } }

        /// <summary>
        /// Loads jQuery if it isn't loaded already
        /// </summary>
        /// <param name="url">the url to load jQuery from</param>
        public static void Load(string url)
        {
            if (!IsLoaded)
            {
                HtmlElement script = HtmlPage.Document.CreateElement("script");
                script.SetAttribute("type", "text/javascript");
                script.SetAttribute("src", url);
                HtmlPage.Document.Body.AppendChild(script);
            }
        }
        /// <summary>
        /// Load jQuery from Microsoft CDN
        /// </summary>
        public static void Load()
        {
            Load("http://ajax.microsoft.com/ajax/jquery/jquery-1.4.2.js");
                      
            if (IsLoaded)
                _internaljQuery = (ScriptObject)HtmlPage.Window.Eval("jQuery");
#pragma warning disable 168
            ScriptObject prototype = LoadScript("jLight.json2.js");
            ScriptObject jl = LoadScript("jLight.jLight.js");
#pragma warning restore 168
        }

        /// <summary>
        /// Gets the <see cref="jLight.jQueryObject"/> with the specified selector.
        /// </summary>
        /// <value></value>
        public jQueryObject this[jQuerySelector selector]
        {
            get { return jQuery.Select(selector); }
        }

        /// <summary>
        /// Selects the specified selector.
        /// </summary>
        /// <param name="selector">The selector.</param>
        /// <returns></returns>
        public static jQueryObject Select(jQuerySelector selector)
        {
            return Call<ScriptObject>(selector, string.Empty, false);
        }

        /// <summary>
        /// Calls the specified function on the selector.
        /// </summary>
        /// <param name="selector">The selector.</param>
        /// <param name="function">The function.</param>
        /// <param name="parameters">The parameters.</param>
        public static void Call(jQuerySelector selector, string function, params object[] parameters)
        {
            Call<object>(selector, function, parameters);
        }

        /// <summary>
        /// Calls the specified function on the selector.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="selector">The selector.</param>
        /// <param name="function">The function.</param>
        /// <param name="parameters">The parameters.</param>
        /// <returns></returns>
        public static T Call<T>(jQuerySelector selector, string function, params object[] parameters)
        {
            return Call<T>(selector, function, false, parameters);
        }

        /// <summary>
        /// Calls the specified function selector with a check if jQuery is loaded
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="selector">The selector.</param>
        /// <param name="function">The function.</param>
        /// <param name="checkLoaded">if set to <c>true</c> [check loaded].</param>
        /// <param name="parameters">The parameters.</param>
        /// <returns></returns>
        public static T Call<T>(jQuerySelector selector, string function, bool checkLoaded, params object[] parameters)
        {
            if (checkLoaded)
            {
                if (!jQuery.IsLoaded) return default(T);
            }
            return (T)HtmlPage.Window.Eval(BuildExpression(selector, function, parameters));
        }

        /// <summary>
        /// Builds a jQuery expression.
        /// </summary>
        /// <param name="selector">The selector.</param>
        /// <param name="function">The function.</param>
        /// <param name="parameters">The parameters.</param>
        /// <returns></returns>
        public static string BuildExpression(jQuerySelector selector, string function, params object[] parameters)
        {
            var jQueryBuilder = new StringBuilder("jQuery('");
            jQueryBuilder.Append(selector);
            jQueryBuilder.Append("')");
            if (!string.IsNullOrEmpty(function))
            {
                jQueryBuilder.Append('.');
                jQueryBuilder.Append(function);
                jQueryBuilder.Append('(');

                for (int index = 0; index < parameters.Length; index++)
                {
                    var parameter = parameters[index];

                    if (parameter is string || parameter is char) jQueryBuilder.Append("'");
                    jQueryBuilder.Append(parameter);
                    if (parameter is string || parameter is char) jQueryBuilder.Append("'");

                    if (index < parameters.Length - 1)
                    {
                        jQueryBuilder.Append(',');
                    }
                }
                jQueryBuilder.Append(')');
            }
            return jQueryBuilder.ToString();

        }


        /// <summary>
        /// (!Not implemented) Gets the specified URL.
        /// </summary>
        /// <param name="url">The URL.</param>
        /// <param name="function">The function.</param>
        /// <returns></returns>       
        /// <exception cref="NotImplementedException">jQuery.Get is not implemented yet...</exception>
        public static jQueryObject Get(string url, Func<object, object> function)
        {
            throw new NotImplementedException("jQuery.Get is not implemented yet...");
        }
        
        /// <summary>
        /// Gets the json.
        /// </summary>
        /// <param name="url">The URL.</param>
        /// <param name="callback">The callback.</param>
        /// <returns></returns>
        public static string GetJson(string url, Action<JsonValue> callback)
        {
            var jLightJSHelper = (ScriptObject)HtmlPage.Window.Eval("jLight");
            var sqr = (string) jLightJSHelper.Invoke("getJson", url, string.Empty, jQueryFunction.CreateCallbackJson(callback));
            return sqr;
        }

        /// <summary>
        /// Gets the json, but uses the "jsonp" datatype.
        /// </summary>
        /// <param name="url">The URL.</param>
        /// <param name="callback">The callback.</param>
        /// <returns></returns>
        public static string GetJsonP(string url, Action<JsonValue> callback)
        {
            var jLightJSHelper = (ScriptObject)HtmlPage.Window.Eval("jLight");
            var sqr = (string)jLightJSHelper.Invoke("getJsonP", url, string.Empty, jQueryFunction.CreateCallbackJson(callback));
            return sqr;
        }

        /// <summary>
        /// Gets the XML.
        /// </summary>
        /// <param name="url">The URL.</param>
        /// <param name="callback">The callback.</param>
        /// <returns></returns>
        public static string GetXml(string url, Action<XDocument> callback)
        {
            var jLightJSHelper = (ScriptObject)HtmlPage.Window.Eval("jLight");
            var sqr = (string)jLightJSHelper.Invoke("getXml", url, string.Empty, 
                    jQueryFunction.CreateCallbackString(callback));
            return sqr;
        }

        /// <summary>
        /// returns itself from script
        /// </summary>
        /// <value>The this.</value>
        public static jQueryObject This
        {
            get { return (ScriptObject)HtmlPage.Window.Eval("this"); }
        }
    }
}